#include <all_header.h>
static ring_buffer_handle_t handle;
static SemaphoreHandle_t sem_mutex;
static SemaphoreHandle_t sem_dma;

static void channel3_transfer_complete(DMA_HandleTypeDef *dma) {
	ring_buffer_write_cmplt_callback(handle, dma);
}

static void channel4_transfer_complete(DMA_HandleTypeDef *dma) {
	ring_buffer_read_cmplt_callback(handle, dma);
}

static void transfer_failed(DMA_HandleTypeDef *dma) {
	ASSERT(0);
}

void console_write_task_send_cmplt_callback(void *uart) {
	BaseType_t val = pdFALSE;
	ASSERT(xSemaphoreGiveFromISR(sem_dma,&val)== pdTRUE);
}

void console_write_task_init(void) {
	sem_mutex = xSemaphoreCreateMutex();
	ASSERT(sem_mutex);
	sem_dma = xSemaphoreCreateBinary();
	ASSERT(sem_dma);

	handle = ring_buffer_create(CONSOLE_WRITE_BUFFER_SIZE,
			&handle_GPDMA1_Channel3, &handle_GPDMA1_Channel4);
	ASSERT(handle);
	HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel3, HAL_DMA_XFER_CPLT_CB_ID,
			channel3_transfer_complete);
	HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel4, HAL_DMA_XFER_CPLT_CB_ID,
			channel4_transfer_complete);
	HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel3, HAL_DMA_XFER_ERROR_CB_ID,
			transfer_failed);
	HAL_DMA_RegisterCallback(&handle_GPDMA1_Channel4, HAL_DMA_XFER_ERROR_CB_ID,
			transfer_failed);

}

void console_write_task_run(void *arg) {
	static uint8_t buffer[CONSOLE_LOG_BUFFER_SIZE];
	while (true) {
		int size = ring_buffer_read(handle, buffer, sizeof(buffer),
		portMAX_DELAY);
		ASSERT(size > 0);
		// write dma
		ASSERT(HAL_UART_Transmit_DMA(&huart1, buffer, size) == HAL_OK);
		// wait
		ASSERT(xSemaphoreTake(sem_dma,portMAX_DELAY) == pdTRUE);
	}
}

void console_write_task_write(const char *fmt, ...) {
	static uint8_t buffer[CONSOLE_LOG_BUFFER_SIZE];

	ASSERT(xSemaphoreTake(sem_mutex,portMAX_DELAY) == pdTRUE);

	va_list valist;
	va_start(valist, fmt);
	int m = vsnprintf(buffer, sizeof(buffer), fmt, valist);
	va_end(valist);

	if (m > 0) {
		ASSERT(m <= ring_buffer_get_available_size(handle));
		ASSERT(ring_buffer_write(handle, buffer, m) == m);
	}

	ASSERT(xSemaphoreGive(sem_mutex) == pdTRUE);
}

void console_write_task_write2(uint8_t *buffer, uint32_t size) {
	ASSERT(xSemaphoreTake(sem_mutex,portMAX_DELAY) == pdTRUE);
	ASSERT(size <= ring_buffer_get_available_size(handle));
	ASSERT(ring_buffer_write(handle, buffer, size) == size);
	ASSERT(xSemaphoreGive(sem_mutex) == pdTRUE);
}

void console_write_task_sync_write(const uint8_t *fmt, ...) {
	static uint8_t buffer[CONSOLE_LOG_BUFFER_SIZE];
	va_list valist;
	va_start(valist, fmt);
	int m = vsnprintf(buffer, sizeof(buffer), fmt, valist);
	va_end(valist);
	if (m > 0) {
		ASSERT(HAL_UART_Transmit(&huart1, buffer, m, 5000) == HAL_OK);
	}
}
